package com.bugsnag.ohos;

import ohos.app.Context;
import ohos.app.IAbilityManager;
import ohos.bundle.ApplicationInfo;
import ohos.bundle.IBundleManager;

import com.bugsnag.ohos.internal.ImmutableConfig;
import com.bugsnag.ohos.util.OhosLog;

import java.util.HashMap;
import java.util.Map;

/**
 * Collects various data on the application state
 *
 * @since 2021-07-02
 */
public class AppDataCollector {
    /**
     * currentTimeMillis
     */
    public static final long START_TIME_MS = System.currentTimeMillis();
    String codeBundleId;
    Context appContext;
    private IBundleManager packageManager;
    private ImmutableConfig config;
    private SessionTracker sessionTracker;
    private IAbilityManager abilityManager;
    private LaunchCrashTracker launchCrashTracker;
    private Logger logger;
    private String packageName;
    private boolean bgWorkRestricted;
    private String binaryArch;
    private String appName;
    private String releaseStage;
    private String versionName;

    /**
     * constructor
     *
     * @param appContext
     * @param packageManager
     * @param config
     * @param sessionTracker
     * @param abilityManager
     * @param launchCrashTracker
     * @param logger
     */
    public AppDataCollector(Context appContext, IBundleManager packageManager, ImmutableConfig config,
                            SessionTracker sessionTracker, IAbilityManager abilityManager,
                            LaunchCrashTracker launchCrashTracker, Logger logger) {
        this.appContext = appContext;
        this.packageManager = packageManager;
        this.config = config;
        this.sessionTracker = sessionTracker;
        this.abilityManager = abilityManager;
        this.launchCrashTracker = launchCrashTracker;
        this.logger = logger;
        packageName = appContext.getBundleName();
        bgWorkRestricted = isBackgroundWorkRestricted();
        appName = getAppName();
        releaseStage = config.getReleaseStage();
        versionName = config.getAppVersion();
    }

    public String getCodeBundleId() {
        return codeBundleId;
    }

    public void setCodeBundleId(String codeBundleId) {
        this.codeBundleId = codeBundleId;
    }

    /**
     * The name of the running Ohos app, from ohos:label in
     * config.json
     */
    private String getAppName() {
        ApplicationInfo copy = config.getAppInfo();
        String name = "null";
        if (packageManager != null && copy != null) {
            name = config.getAppInfo().getLabel();
        }
        return name;
    }

    private boolean isBackgroundWorkRestricted() {
        if (abilityManager == null) {
            return false;
        }
        if (abilityManager.isBackgroundRunningRestricted()) {
            return true;
        }
        return false;
    }

    /**
     * generate App
     *
     * @return App
     */
    public App generateApp() {
        return new App(config, binaryArch, packageName, releaseStage,
            versionName, codeBundleId);
    }

    /**
     * generate App With State
     *
     * @return AppWithState
     */
    public AppWithState generateAppWithState() {
        boolean inForeground = sessionTracker.isInForeground();
        long durationInForeground = calculateDurationInForeground(inForeground);
        return new AppWithState(
            config, binaryArch, packageName, releaseStage, versionName, codeBundleId,
            getDurationMs(), durationInForeground, inForeground,
            launchCrashTracker.isLaunching()
        );
    }

    /**
     * get App Data Meta data
     *
     * @return Meta data
     */
    public Map<String, Object> getAppDataMetadata() {
        Map map = new HashMap<String, Object>();
        map.put("name", getAppName());
        map.put("activeScreen", getActiveScreenClass());
        map.put("memoryUsage", getMemoryUsage());
        map.put("lowMemory", isLowMemory());
        if (bgWorkRestricted) {
            map.put("backgroundWorkRestricted", bgWorkRestricted);
        }
        return map;
    }

    public String getActiveScreenClass() {
        return sessionTracker.getContextActivity();
    }

    private long getMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }

    /**
     * Check if the device is currently running low on memory.
     */
    private boolean isLowMemory() {
        if (abilityManager != null) {
            int appMemory = abilityManager.getAppMemory();
            int appLargeMemory = abilityManager.getAppLargeMemory();
            OhosLog.d("AppDataCollector", "appMemory :%d", appMemory);
            OhosLog.d("AppDataCollector", "appLargeMemory :%d", appLargeMemory);
            return appMemory < 10;
        }
        return false;
    }

    public void setBinaryArch(String binaryArch) {
        this.binaryArch = binaryArch;
    }

    /**
     * Calculates the duration the app has been in the foreground
     *
     * @return the duration in ms
     */

    public long calculateDurationInForeground() {
        return calculateDurationInForeground(sessionTracker.isInForeground());
    }

    /**
     * calculate Duration In Foreground
     *
     * @param inForeground
     * @return Duration
     */
    public long calculateDurationInForeground(boolean inForeground) {
        if (!inForeground) {
            return 0;
        }
        long nowMs = System.currentTimeMillis();
        long durationMs = 0L;
        long sessionStartTimeMs = sessionTracker.getLastEnteredForegroundMs();
        if (inForeground && sessionStartTimeMs != 0L) {
            durationMs = nowMs - sessionStartTimeMs;
        }
        return durationMs > 0 ? durationMs : 0;
    }

    /**
     * Get the time in milliseconds since Bugsnag was initialized, which is a
     * good approximation for how long the app has been running.
     *
     * @return DurationMs
     */
    public static long getDurationMs() {
        return System.currentTimeMillis() - START_TIME_MS;
    }
}
